﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Bridge.Base.Utilities;
using Bridge.UI.Utilities;
using Pathfinder.Base.Constructs;
using Pathfinder.Base.Importer;
using Pathfinder.Base.Utilities;

namespace Pathfinder.Converters.HeroLab
{
    /// <summary>
    /// StatblockConverter for HeroLab.
    /// </summary>
    public class HeroLabStatblockConverter : PFStatblockImporter
    {
        /// <summary>
        /// Gets the name of the converter.
        /// </summary>
        public override string Name
        {
            get { return "HeroLab"; }
        }

        /// <summary>
        /// Gets the description of the converter.
        /// </summary>
        public override string Description
        {
            get
            {
                return "HeroLab Statblock Importer\n" +
                    "Created by Zachare Sylvestre (Imper1um)";
            }
        }

        /// <summary>
        /// Finds the Speeds in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="regex">Regex to use</param>
        /// <returns>Dictionary of SpeedType found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or regex is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input or regex is empty.</exception>
        public override Dictionary<SpeedType, int> GetSpeeds(string input)
        {
            input.ThrowIfNullOrEmpty("input");

            Dictionary<SpeedType, int> speeds = new Dictionary<SpeedType, int>();
            foreach (SpeedType speedType in Enum.GetValues(typeof(SpeedType)))
            {
                string findRegex = string.Format(@"(?<={0} )\d+", speedType == SpeedType.Base ? "Spd" : speedType.ToString());
                string foundInfo = input.FindFirstMatch(findRegex);
                if (!string.IsNullOrEmpty(foundInfo))
                {
                    speeds.Add(speedType, int.Parse(foundInfo));
                }
            }

            return speeds;
        }

        /// <summary>
        /// Parses a skill string.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <param name="character">Character to use for stats.</param>
        /// <returns>Skill found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input or character is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public override Skill GetSkill(string input, PathfinderCharacter character)
        {
            input.ThrowIfNullOrEmpty("input");
            if (character == null) throw new ArgumentNullException("character");

            string regex = @"[a-zA-Z][a-zA-Z ]+?((?=: )|(?= \()|(?= \+)|(?= \-)|(?=$))";

            string skillName = input.FindFirstMatch(regex);
            if (skillName == null) return null;
            int skillAmount = int.Parse(input.FindFirstMatch(@"\d+"));
            string skillSubName = input.FindFirstMatch(@"(?<=:).+?((?= +)|(?= -)|(?= -))");
            int level = character.TotalHitDice;

            if (!string.IsNullOrEmpty(skillSubName))
            {
                skillSubName = skillSubName.Trim();
            }
            if (!string.IsNullOrEmpty(skillSubName) && skillSubName.Equals("any one", StringComparison.OrdinalIgnoreCase))
            {
                Random random = new Random();
                ReadOnlyCollection<string> subskills = Skill.GetAllSubskillNames(skillName);
                int randomSkill = random.Next(0, subskills.Count - 1);
                skillSubName = subskills[randomSkill];
            }
            
            Skill skill = Skill.CreateBaseSkill(skillName, skillSubName);
            skillAmount -= character.TotalStats[skill.BaseStatType].GetBonus();
            if (skillAmount > 4)
            {
                skill.IsClassSkill = true;
                skillAmount -= 3;
            }
            if (skillAmount > 0)
            {
                if (level >= skillAmount)
                {
                    skill.Ranks = level > skillAmount ? skillAmount : level;
                    skillAmount -= level > skillAmount ? skillAmount : level;
                }
                else
                {
                    skill.Ranks = skillAmount;
                    skillAmount = 0;
                }
            }
            if (skill.Ranks > level)
            {
                int removeAmount = skill.Ranks - level;
                skill.Ranks -= removeAmount;
                skill.MiscBonus += removeAmount;
            }
            skill.MiscBonus += skillAmount;

            return skill;
        }

        /// <summary>
        /// Finds the Stats in a Statblock.
        /// </summary>
        /// <param name="input">Statblock to search.</param>
        /// <returns>Stats found; null if nothing is found.</returns>
        /// <exception cref="ArgumentNullException">Thrown if input is null.</exception>
        /// <exception cref="ArgumentException">Thrown if input is empty.</exception>
        public override Dictionary<StatType, int> GetStats(string input)
        {
            input.ThrowIfNullOrEmpty("input");
            string regex = @"(?<={0} )\d+";
            string primaryRegex = @"(?<={0} )\d+/\d+";

            Dictionary<StatType, int> stats = new Dictionary<StatType, int>();
            foreach (StatType statType in Enum.GetValues(typeof(StatType)))
            {
                string regexInput = string.Format(regex, statType.GetUIDisplayAttribute().ConversionName);
                string primaryRegexInput = string.Format(primaryRegex, statType.GetUIDisplayAttribute().ConversionName);
                string match = input.FindFirstMatch(primaryRegexInput) ?? input.FindFirstMatch(regexInput);
                int number = 10;
                if (match != null)
                {
                    string[] matches = match.Split('/');
                    if (matches.Length > 1)
                    {
                        int.TryParse(matches[1], out number);
                    }
                    else
                    {
                        int.TryParse(matches[0], out number);
                    }
                }
                stats.Add(statType, number);
            }
            return stats;
        }
    }
}
